package main

import (
	"context"
	"embed"
	"geekai/api/handler/admin"
	"geekai/api/handler/front"
	"geekai/core"
	_ "geekai/docs"
	logger2 "geekai/logger"
	"geekai/service"
	"geekai/service/crawler"
	"geekai/service/dalle"
	"geekai/service/mj"
	"geekai/service/openai"
	"geekai/service/oss"
	"geekai/service/payment"
	"geekai/service/sd"
	"geekai/service/sms"
	"geekai/service/suno"
	"geekai/service/video"
	"github.com/lionsoul2014/ip2region/binding/golang/xdb"
	swaggerFiles "github.com/swaggo/files"
	ginSwagger "github.com/swaggo/gin-swagger"
	"go.uber.org/fx"
	"io"
	"os"
	"os/signal"
	"strconv"
	"syscall"
	"time"
)

var log = logger2.GetLogger()

//go:embed res
var xdbFS embed.FS

func NewConfigParams() core.ConfigParams {
	// 从环境变量中读取配置文件地址
	configFile := os.Getenv("CONFIG_FILE")
	if configFile == "" {
		configFile = "config.toml"
	}
	// 从环境变量中读取是否debug模式
	debug, _ := strconv.ParseBool(os.Getenv("APP_DEBUG"))
	log.Info("loading config file：", configFile)
	configParam := core.ConfigParams{
		ConfigFile: configFile,
		Debug:      debug,
	}
	return configParam
}

// @title           copy-geek-ai
// @version         1.0
// @description     从0到1实现的geekai
// @termsOfService  http://swagger.io/terms/

// @contact.name   API Support
// @contact.url    http://www.swagger.io/support
// @contact.email  1175974811@qq.com

// @license.name  Apache 2.0
// @license.url   http://www.apache.org/licenses/LICENSE-2.0.html

// @host      localhost:7788
// @BasePath

// @securityDefinitions.apikey AdminApiKeyAuth
// @in header
// @name Admin-Authorization

// @securityDefinitions.apikey ApiKeyAuth
// @in header
// @name Authorization

// @externalDocs.description  OpenAPI
// @externalDocs.url          https://swagger.io/resources/open-api/
func main() {
	configParam := NewConfigParams()
	// 如果不是debug模式就捕获panic错误
	if !configParam.Debug {
		defer func() {
			if err := recover(); err != nil {
				log.Error("panic Error：", err)
			}
		}()
	}
	app := fx.New(
		// 提供配置参数
		fx.Provide(func() core.ConfigParams {
			return configParam
		}),
		fx.Provide(func() embed.FS {
			return xdbFS
		}),
		// 创建 Ip2Region 对象
		fx.Provide(func() (*xdb.Searcher, error) {
			file, err := xdbFS.Open("res/ip2region.xdb")
			if err != nil {
				return nil, err
			}
			cBuff, err := io.ReadAll(file)
			if err != nil {
				return nil, err
			}
			return xdb.NewWithBuffer(cBuff)
		}),
		core.RegisterAppServerObj(),
		core.RegisterStoreObj(),
		core.RegisterConfigObj(),
		core.RegisterAppLifecycleObj(),
		fx.Invoke(func(s *core.AppServer) {
			s.Engine.GET("swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
		}),
		// 注册文件上传管理器
		oss.RegisterUploaderManagerObj(),
		// 注册短信服务
		sms.RegisterSMSManagerObj(),
		// 注册 Service
		service.RegisterServiceObj(),
		// 注册大模型对话 Service
		openai.RegisterOpenAIChatObj(),
		// 注册 Dalle 模型 Service
		dalle.RegisterDalleServiceObj(),
		// 注册 MJ 模型 Service
		mj.RegisterMJServiceObj(),
		// 注册 SD 模型 Service
		sd.RegisterSDServiceObj(),
		// 注册 Suno 模型 Service
		suno.RegisterSunoServiceObj(),
		// 注册视频模型 Service
		video.RegisterVideoServiceObj(),
		// 注册爬虫 Service
		crawler.RegisterCrawlerManagerServiceObj(),
		// 注册支付 Service
		payment.RegisterPayManagerObj(),
		// 注册后台API
		admin.RegisterAdminHandlerObj(),
		// 注册前台API
		front.RegisterFrontHandlerObj(),
	)
	// 启动应用程序
	go func() {
		if err := app.Start(context.Background()); err != nil {
			log.Fatal("应用程序启动失败：", err)
		}
	}()
	// 创建一个信号通道
	quit := make(chan os.Signal, 1)
	// 注册要监听的信号
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
	// 阻塞等待信号
	<-quit
	// 创建超时上下文
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	// 使用超时上下文停止应用
	if err := app.Stop(ctx); err != nil {
		log.Fatal("关闭应用程序失败：", err)
	}
}
